﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.SharePoint.Client;
using System.Net;
using System.Data;

namespace SharePointClientHelper
{
    public class SPClientHelper
    {
        private static SPClientHelper _instance;
        private ClientContext context;
        public string SiteTitle { get; set; }

        private SPClientHelper(string siteurl, string domain, string username, string password)
        {
            context = new ClientContext(siteurl);
            context.Credentials = new NetworkCredential(username, password, domain);            
        }

        ~SPClientHelper()
        {
            if (context != null)
            {
                context.Dispose();
            }
        }

        public static SPClientHelper SetSPClientHelper(string siteurl, string domain, string username, string password)
        {               
            try
            {
                _instance = new SPClientHelper(siteurl, domain, username, password);
                _instance.context.Load(_instance.context.Web);
                _instance.context.Load(_instance.context.Web.CurrentUser);
                _instance.context.ExecuteQuery();
                _instance.SiteTitle = _instance.context.Web.Title;
            }
            catch
            {
                _instance = null;
            }

            return _instance;
        }

        public static SPClientHelper GetSPClientHelper()
        {
            try
            {                
                _instance.context.Load(_instance.context.Web);
                _instance.context.Load(_instance.context.Web.CurrentUser);
                _instance.context.ExecuteQuery();
                _instance.SiteTitle = _instance.context.Web.Title;
            }
            catch
            {
                _instance = null;
            }

            return _instance;
        }

        public string GetCurrentUser()
        {
            return context.Web.CurrentUser.Title;
        }

        public string GetSiteUrl()
        {
            return context.Web.Url;
        }

        public List<UpdatedUsers> UpdateUserInGroup(string GroupName, List<MyUser> listUsers)
        {
            Group selectedGroup = this.context.Web.SiteGroups.GetByName(GroupName);
            context.Load(selectedGroup);
            context.ExecuteQuery();

            List<UpdatedUsers> listUpdatedUsers = new List<UpdatedUsers>();
            foreach (MyUser objUser in listUsers)
            {
                bool _setLoginName = true;
                string strLoginName = objUser.LoginName;

                UpdatedUsers objUpdatedUser = new UpdatedUsers()
                {
                    Name = objUser.Name,
                    EmailId = objUser.EmailId,
                    LoginName = objUser.LoginName,
                    GroupName = GroupName
                };

                if (!string.IsNullOrEmpty(strLoginName))
                {
                    try
                    {
                        User csvUser = context.Web.EnsureUser(strLoginName);
                        context.Load(csvUser);
                        context.ExecuteQuery();

                        selectedGroup.Users.AddUser(csvUser);
                        selectedGroup.Update();
                        context.ExecuteQuery();

                        objUpdatedUser.Status = "Added";
                        if (_setLoginName)
                            objUpdatedUser.LoginName = csvUser.LoginName;
                    }
                    catch (Exception ex)
                    {
                        objUpdatedUser.Status = "Error: " + ex.Message;
                    }
                }
                else
                {
                    objUpdatedUser.Status = "Not Found";
                }

                listUpdatedUsers.Add(objUpdatedUser);
            }


            return listUpdatedUsers;
        }

        public DataTable UpdateUserInGroup(string GroupName, DataTable dtUsers)
        {
            Group selectedGroup = this.context.Web.SiteGroups.GetByName(GroupName);
            context.Load(selectedGroup);
            context.ExecuteQuery();

            dtUsers.Columns.Add(new DataColumn("Status", typeof(string)));
            dtUsers.Columns.Add(new DataColumn("LoginName", typeof(string)));
            foreach (DataRow dr in dtUsers.Rows)
            {
                bool _setLoginName = false;
                string strLoginName = string.Empty;

                if (!string.IsNullOrEmpty(Convert.ToString(dr["EmailId"])))
                {
                    string Email = Convert.ToString(dr["EmailId"]);
                    string[] splitMail = Email.Split('@');

                    if (splitMail.Length > 1)
                        strLoginName = splitMail[1].Substring(0, splitMail[1].IndexOf(".")) + "\\" + splitMail[0];

                    _setLoginName = true;
                }

                if (!string.IsNullOrEmpty(strLoginName))
                {
                    try
                    {
                        User csvUser = context.Web.EnsureUser(strLoginName);
                        context.Load(csvUser);
                        context.ExecuteQuery();

                        selectedGroup.Users.AddUser(csvUser);
                        selectedGroup.Update();
                        context.ExecuteQuery();

                        dr["Status"] = "Added";
                        if (_setLoginName)
                            dr["LoginName"] = csvUser.LoginName;
                    }
                    catch (Exception ex)
                    {
                        dr["Status"] = "Error: " + ex.Message;
                    }
                }
                else
                {
                    dr["Status"] = "Not Found";
                }
            }
            dtUsers.AcceptChanges();

            return dtUsers;
        }

        public DataTable UpdateUserFromCSV(DataTable dtUsers)
        {           
            dtUsers.Columns.Add(new DataColumn("Status", typeof(string)));
            dtUsers.Columns.Add(new DataColumn("LoginName", typeof(string)));


            foreach (DataRow dr in dtUsers.Rows)
            {
                string strGroupName = Convert.ToString(dr["GroupName"]);
                Group selectedGroup = this.context.Web.SiteGroups.GetByName(strGroupName);
                context.Load(selectedGroup);
                context.ExecuteQuery();

                bool _setLoginName = false;
                string strLoginName = string.Empty;

                if (!string.IsNullOrEmpty(Convert.ToString(dr["EmailId"])))
                {
                    string Email = Convert.ToString(dr["EmailId"]);
                    string[] splitMail = Email.Split('@');

                    if (splitMail.Length > 1)
                        strLoginName = splitMail[1].Substring(0, splitMail[1].IndexOf(".")) + "\\" + splitMail[0];

                    //MyUser objUser = new MyUser()
                    //{
                    //    EmailId = Email,
                    //    Name = Convert.ToString(dr["Name"])
                    //};

                    //strLoginName = objUser.LoginName;

                    _setLoginName = true;
                }

                if (!string.IsNullOrEmpty(strLoginName))
                {
                    try
                    {
                        User csvUser = context.Web.EnsureUser(strLoginName);
                        context.Load(csvUser);
                        context.ExecuteQuery();

                        selectedGroup.Users.AddUser(csvUser);
                        selectedGroup.Update();
                        context.ExecuteQuery();

                        dr["Status"] = "Added";
                        if (_setLoginName)
                            dr["LoginName"] = csvUser.LoginName;
                    }
                    catch (Exception ex)
                    {
                        dr["Status"] = "Error: " + ex.Message;
                    }
                }
                else
                {
                    dr["Status"] = "Not Found";
                }
            }
            dtUsers.AcceptChanges();

            return dtUsers;
        }
        public List<MyGroup> GetSiteGroups()
        {
            GroupCollection grpColl = context.Web.SiteGroups;
            context.Load(grpColl);
            context.ExecuteQuery();

            List<MyGroup> lstMyGroups = new List<MyGroup>();
            foreach (Group group in grpColl)
            {
                MyGroup mgp = new MyGroup()
                {
                    Title = group.Title,
                    ID = group.Id
                };
                lstMyGroups.Add(mgp);
            }

            return lstMyGroups;
        }

        public List<MyGroup> GetWebGroups()
        {
            GroupCollection grpColl = context.Web.SiteGroups;
            context.Load(grpColl);
            context.ExecuteQuery();

            List<MyGroup> lstMyGroups = new List<MyGroup>();
            foreach (Group group in grpColl)
            {
                MyGroup mgp = new MyGroup()
                {
                    Title = group.Title,
                    ID = group.Id
                };
                lstMyGroups.Add(mgp);
            }

            return lstMyGroups;
        }

        public bool Logout()
        {
            if (context != null)
                context.Dispose();
            SiteTitle = string.Empty;
            return true;
        }

        public List<MyDocumentLibrary> GetAllDocumentLibrary()
        {
            ListCollection listColl = context.Web.Lists;
            context.Load(listColl);
            context.ExecuteQuery();

            List<MyDocumentLibrary> lstMyDocLib = new List<MyDocumentLibrary>();
            foreach (List lst in listColl)
            {
                if (lst.BaseType == BaseType.DocumentLibrary && !lst.Hidden)
                {
                    
                    MyDocumentLibrary objDocLib = new MyDocumentLibrary()
                    {
                        Name = lst.Title,
                        GUID = lst.Id.ToString()
                    };

                    lstMyDocLib.Add(objDocLib);
                }
            }
            return lstMyDocLib;
        }

        public List<MyDocumentLibrary> GetAllDocuments(string DocumentLibrary)
        {
            List docLib = context.Web.Lists.GetByTitle(DocumentLibrary);

            CamlQuery objCamlquery = new CamlQuery();
            objCamlquery.ViewXml = "<View>"
   + "<ViewFields>"
   + "  <FieldRef Name='Title' /><FieldRef Name='FileLeafRef' />"
   + "</ViewFields>"
   + "</View>";

            ListItemCollection itmColl = docLib.GetItems(objCamlquery);
            context.Load(docLib);
            context.Load(itmColl);
            context.ExecuteQuery();

            List<MyDocumentLibrary> lstMyDocLib = new List<MyDocumentLibrary>();
            foreach (ListItem lstItem in itmColl)
            {
                    MyDocumentLibrary objDocLib = new MyDocumentLibrary()
                    {
                        Name = lstItem["FileLeafRef"].ToString(),
                        GUID = lstItem.Id.ToString()
                    };

                    lstMyDocLib.Add(objDocLib);
            }
            return lstMyDocLib;
        }

        public List<MyUser> GetAllUsersInGroup(string GroupName)
        {
            List<MyUser> listUsers = new List<MyUser>();

            Group selectedGroup = this.context.Web.SiteGroups.GetByName(GroupName);
            context.Load(selectedGroup);
            context.Load(selectedGroup.Users);
            context.ExecuteQuery();

            foreach(User usr in selectedGroup.Users)
            {
                MyUser objUser = new MyUser()
                {
                    Name = usr.Title,
                    EmailId=usr.Email,
                    LoginName=usr.LoginName
                };

                listUsers.Add(objUser);
            }

            return listUsers;
        }

        public List<MyPermission> GetAllPermissions()
        {
            List<MyPermission> lstPerm = new List<MyPermission>();
            lstPerm.Add(new MyPermission() { Name = "Read", ID = "1" });
            lstPerm.Add(new MyPermission() { Name = "Contribute", ID = "2" });
            lstPerm.Add(new MyPermission() { Name = "Design", ID = "3" });
            lstPerm.Add(new MyPermission() { Name = "User Admin", ID = "4" });
            lstPerm.Add(new MyPermission() { Name = "Full Control", ID = "5" });

            return lstPerm;
        }

        public List<UpdatedRolePrinciple> SetRole(List<RolePrinciple> rolePrinciples, string permission)
        {
            List<UpdatedRolePrinciple> upRP = new List<UpdatedRolePrinciple>();
            foreach (RolePrinciple role in rolePrinciples)
            {
                UpdatedRolePrinciple urp = new UpdatedRolePrinciple() { Name = role.Name, Permission = role.Permission, Type = role.Type, Site = role.Site };
                try
                {
                    if (!string.IsNullOrEmpty(urp.Site))
                    {
                        context = new ClientContext(urp.Site);
                    }

                    RoleDefinition readDef = context.Web.RoleDefinitions.GetByName(permission);
                    RoleDefinitionBindingCollection roleDefCollection = new RoleDefinitionBindingCollection(context);
                    roleDefCollection.Add(readDef);

                    if (urp.Type == "SPGroup")
                    {
                        Principal group = context.Web.SiteGroups.GetByName(urp.Name);
                        RoleAssignment newRoleAssignment = context.Web.RoleAssignments.Add(group, roleDefCollection);
                    }
                    else
                    {
                        // Assume that we have a SiteUser with Login user. 
                        Principal user = context.Web.SiteUsers.GetByEmail(urp.Name);
                        RoleAssignment newRoleAssignment = context.Web.RoleAssignments.Add(user, roleDefCollection);                        
                    }

                    context.ExecuteQuery();
                    urp.Status = "Added";
                }
                catch (Exception ex)
                {
                    urp.Status = "Error: " + ex.Message;
                }

                upRP.Add(urp);
            }

            return upRP;
        }
    }
}
